/*
 * 巴法科技:2022-11-22
 * 支持巴法app和小程序配网，长按按键可重新配网
 */
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <OneWire.h>
#include <DallasTemperature.h>

WiFiClient client_bemfa_WiFiClient;
HTTPClient http_bemfa_HTTPClient;
// 巴法云服务器地址默认即可
#define TCP_SERVER_ADDR "bemfa.com"
// 服务器端口，tcp创客云端口8344
#define TCP_SERVER_PORT "8344"
// 最大字节数
#define MAX_PACKETSIZE 512
// 设置心跳值30s
#define KEEPALIVEATIME 30 * 1000
// tcp客户端相关初始化，默认即可
String TcpClient_Buff = "";
unsigned int TcpClient_BuffIndex = 0;
unsigned long TcpClient_preTick = 0;
unsigned long preHeartTick = 0;    // 心跳
unsigned long preTCPStartTick = 0; // 连接

bool preTCPConnected = false;

// 相关函数初始化
void saveConfig();

// 连接WIFI
void initWiFi();
void doWiFiTick();

// TCP初始化连接
void doTCPClientTick();
void startTCPClient();
void sendtoTCPServer();
void doHttpStick(String msg);
void sendtoTCPServer(String p);

String UID = "4892bd7fe005ecbbccf35929157ec7e7";
String TOPIC1 = ""; // 增压泵控制器
String TOPIC2 = ""; // 球阀

String wifi_name = "15367660966";  // WIFI名称，区分大小写，不要写错
String wifi_password = "15367660"; // WIFI密码
String Name = "增压泵控制器";      // 设备名称

const int LedBlink = 13;   // 指示灯引脚，可自行修改，如果没有指示灯，建议删除指示灯相关代码
const int buttonPin = 0;   // 定义按钮输出引脚
const int QFkaiPin = 5;    // 定义球阀开关输出引脚
const int QFguanPin = 15;  // 定义球阀开关输出引脚
const int liuShuiPin = 16; // 定义流水状态输入引脚
const int YaliPin = A0;    // 定义水压输入引脚
const int WenDuPin = 14;   // 定义水压输入引脚
const int ZYBStatePin = 4; // 定义增压状态输入引脚

float ShuiWenValue = 0; // 温度
float ShuiYaValue = 0;  // 水压值
int ShuiWeiValue = 0;   // 水位值
bool ZYB_State = false; // 增压状态
bool WiF_State = false; // 流水状态

int f5;
unsigned long checkPinStatusTick = 0;
OneWire oneWire(WenDuPin);
DallasTemperature sensors(&oneWire);

/**
 * 结构体，用于存储配网信息
 */
struct config_type
{
  uint8_t magic;
  bool QF_State = false;   // 球阀状态
  bool Auto_State = false; // 自动模式
};
config_type config;

#include <Update.h>
#include <ZYB.h>
#include <8266_udp.h>

/**
 * 存储信息
 */
void saveConfig()
{
  EEPROM.begin(256);
  uint8_t *p = (uint8_t *)(&config);
  for (int i = 0; i < sizeof(config); i++)
  {
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
}

/**
 * 加载存储的信息，并检查是否恢复出厂信息
 */
void loadConfig()
{
  EEPROM.begin(256);
  uint8_t *p = (uint8_t *)(&config);
  for (int i = 0; i < sizeof(config); i++)
  {
    *(p + i) = EEPROM.read(i);
  }
  if (config.magic != 0xAA)
  {
    config.magic = 0xAA;
    config.QF_State = false;   // 球阀状态
    config.Auto_State = false; // 自动模式
    saveConfig();
  }
  Serial.print("自动模式:");
  Serial.println(config.Auto_State);
  Serial.print("球阀状态:");
  Serial.println(config.QF_State);
}

/**
 * 初始化wifi信息，并连接路由器网络
 *
 */
void initWiFi()
{
  WiFi.disconnect();                    // 断开连接
  WiFi.mode(WIFI_STA);                  // STA模式
  WiFi.begin(wifi_name, wifi_password); // 连接路由器
}

/*
 *发送数据到TCP服务器
 */
void sendtoTCPServer(String p)
{

  if (!client_bemfa_WiFiClient.connected())
  {
    return;
  }
  client_bemfa_WiFiClient.print(p);
  preHeartTick = millis(); // 心跳计时开始，需要每隔60秒发送一次数据
}

void sendtoTCPServer()
{
  // sensors.requestTemperatures();
  // ShuiWenValue = sensors.getTempCByIndex(0);
  sendtoTCPServer("cmd=2&uid=" + UID + "&topic=" + TOPIC1 + "/up&msg=" + config.QF_State + "#" + ShuiWeiValue + "#" + ShuiYaValue + "#" + ShuiWenValue + "#" + config.Auto_State + "#" + ZYB_State + "#" + WiF_State + "\r\n"); // 推送消息
}

/*
 *初始化和服务器建立连接
 */
void startTCPClient()
{
  String topic = WiFi.macAddress().substring(8); // 取mac地址做主题用
  topic.replace(":", "");                        // 去掉:号
  TOPIC1 = topic + "004";                        // 主题添加类型
  TOPIC2 = topic + "006";                        // 主题添加类型
  static int Count = 0;
  static int failCount = 10;
  if (client_bemfa_WiFiClient.connect(TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT)))
  {
    Serial.println("bemfa.com config ok");
    Serial.printf("%s: %d\r\n", TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT));
    String tcpTemp = "";                                                       // 初始化字符串
    tcpTemp = "cmd=1&uid=" + UID + "&topic=" + TOPIC1 + "," + TOPIC2 + "\r\n"; // 构建订阅指令
    sendtoTCPServer(tcpTemp);                                                  // 发送订阅指令
    Serial.println(tcpTemp);
    tcpTemp = "";                                                              // 清空
    client_bemfa_WiFiClient.setNoDelay(true);
    failCount = 0;
  }
  else
  {
    Count = Count + 1;
    if (failCount < Count) // 如果失败连接10次，重启系统
    {
      // delayRestart(0);
    }
    Serial.print("Failed connected to server:");
    Serial.println(TCP_SERVER_ADDR);
    client_bemfa_WiFiClient.stopAll();
  }
  preTCPStartTick = millis();
}

/*
 *检查数据，发送心跳
 */
void doTCPClientTick()
{
  // 检查是否断开，断开后重连
  if (WiFi.status() != WL_CONNECTED)
  {
    preTCPStartTick = millis();
    return;
  }
  if (!client_bemfa_WiFiClient.connected()) // 断开重连
  {
    if (millis() - preTCPStartTick > 3000) // 重新连接
    {
      startTCPClient();
    }
  }
  else
  {
    if (client_bemfa_WiFiClient.available())
    { // 收数据
      char c = client_bemfa_WiFiClient.read();
      TcpClient_Buff += c;
      TcpClient_BuffIndex++;
      TcpClient_preTick = millis();
      if (TcpClient_BuffIndex >= MAX_PACKETSIZE - 1)
      {
        TcpClient_Buff = "";
        TcpClient_BuffIndex = 0;
        TcpClient_preTick = TcpClient_preTick - 200;
      }
    }
    if (millis() - preHeartTick >= KEEPALIVEATIME)
    {
      // sendtoTCPServer("cmd=0&msg=keep\r\n");
      IPAddress ip = WiFi.localIP();
      char ipStr[16];
      ip.toString().toCharArray(ipStr, 16);
      sendtoTCPServer("cmd=2&uid=" + UID + "&topic=" + TOPIC1 + "/up&msg=" + TOPIC1 + "#" + ipStr + "\r\n"); // 推送消息
    }
    if ((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick >= 10))
    {
      client_bemfa_WiFiClient.flush();
      if (TcpClient_Buff.length() >= 60)
      {
        // Serial.print("接收数据:" + String(TcpClient_Buff.length()) + "字节" + TcpClient_Buff);
        if (TcpClient_Buff.indexOf("update") > 0)
        {
          Serial.println("[update] Update Start......");
          updateBin();
        }
        else if (TcpClient_Buff.indexOf("ZYB_on") > 0 || TcpClient_Buff.indexOf("" + TOPIC1 + "&msg=on") > 0)
        {
          Serial.println("ZYB_on");
          config.Auto_State = true;
          ZYB_onoff(true);
        }
        else if (TcpClient_Buff.indexOf("ZYB_off") > 0 || TcpClient_Buff.indexOf("" + TOPIC1 + "&msg=off") > 0)
        {
          Serial.println("ZYB_off");
          config.Auto_State = false;
          ZYB_onoff(false);
        }
        else if (TcpClient_Buff.indexOf("QF_on") > 0 || TcpClient_Buff.indexOf("" + TOPIC2 + "&msg=on") > 0)
        {
          Serial.println("QF_on");
          QF_onoff(true);
        }
        else if (TcpClient_Buff.indexOf("QF_off") > 0 || TcpClient_Buff.indexOf("" + TOPIC2 + "&msg=off") > 0)
        {
          Serial.println("QF_off");
          ZYB_onoff(false);
          QF_onoff(false);
        }
      }
      TcpClient_Buff = "";
      TcpClient_BuffIndex = 0;
    }
  }
}

/*
  WiFiTick
  检查是否需要初始化WiFi
  检查WiFi是否连接上，若连接成功启动TCP Client
  控制指示灯
*/
void doWiFiTick()
{
  static int wifi = 0;
  static bool startSTAFlag = false;
  static bool taskStarted = false;
  static uint32_t lastWiFiCheckTick = 0;
  if (!startSTAFlag)
  {
    startSTAFlag = true;
    initWiFi();
  }
  // 未连接1s重连
  while (WiFi.status() != WL_CONNECTED)
  {
    if (millis() - lastWiFiCheckTick > 100)
    {
      if (wifi++ >= 600)
      {
        ESP.restart();
        startSTAFlag = false;
      }
      delay(10);
      lastWiFiCheckTick = millis();
      digitalWrite(LedBlink, !digitalRead(LedBlink)); // 切换指示灯状态
    }
    taskStarted = false;
    preTCPConnected = false;
  }
  // 连接成功建立
  if (WiFi.status() == WL_CONNECTED)
  {
    if (taskStarted == false)
    {
      Serial.println("");
      Serial.println("wifi config ok");
      Serial.print("IP: ");
      Serial.println(WiFi.localIP());
      digitalWrite(LedBlink, LOW); // 切换指示灯状态
      startTCPClient();
      taskStarted = true;
    }
  }
}

//  微信消息推送函数
void doHttpStick(String msg)
{
  String type = "2"; // 1表示是预警消息，2表示设备提醒消息
  WiFiClient WiFi;
  HTTPClient http;
  String ApiUrl = "http://api.bemfa.com/api/wechat/v1/"; // 默认 api 网址
  String postData = "uid=" + UID + "&type=" + type + "&device=" + Name + "&msg=" + msg;
  http.begin(WiFi, ApiUrl);                                            // Specify request destination
  http.addHeader("Content-Type", "application/x-www-form-urlencoded"); // Specify content-type header
  http.POST(postData);                                                 // Send the request
  http.end();                                                          // Close connection
}

// 初始化，相当于main 函数
void setup()
{
  Serial.begin(9600);
  Serial.println("");
  Serial.println("Beginning...");
  sensors.begin();
  loadConfig();
  configureUDP();
  pinMode(QFkaiPin, OUTPUT);
  pinMode(QFguanPin, OUTPUT);
  pinMode(ZYBStatePin, INPUT);
  pinMode(LedBlink, OUTPUT);
  digitalWrite(LedBlink, LOW);
}
// 循环
void loop()
{
  ZengYaBang();      // 检查增压泵状态
  doWiFiTick();      // 检查wifi
  doTCPClientTick(); // tcp消息接收
  loop_UDP();        // 发送UDP消息
  delay(1);
}
